/**
 * Definition of peel edge entity.
 *
 * \file edge.hpp
 * \author tomby
 * \date 04-01-2009
 **/

/*  Copyright (C) 2009  Tomas 'tomby' Bily

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */


#ifndef __DBC_EDGE__
#define __DBC_EDGE__

namespace dbc {
  namespace peel {

#define IS_DBC_EDGE(X) IS_DBC_TYPE(X, dbc::peel::Edge)
#define DBC_EDGE(X) DBC_TYPE(X, dbc::peel::Edge)
#define DBC_EDGE_PTR(X) DBC_TYPE_PTR(X, dbc::peel::Edge)

    class Node;

    /*
     *     *                  *                    *<-*
     *     | DOWN             ^ UP                 INTERACT
     *     v SINK             | EMERGE
     *     *                  * 
     *    
     */

    class Edge : public dbc::temporal::StampableEntity
    {
      ENTITY_DEF(Edge);
      
    public:
      typedef enum 
	{
	  EMERGE,
	  SINK,
	  INTERACT
	} EdgeType;

      typedef enum
	{
	  RED,
	  GREEN,
	  BLUE
	} ColorType;

    private:
      EdgeType	e_type;
      int	sink_level;
      int	color;

    protected:
      Edge (EdgeType etype, int col)
	: e_type (etype), sink_level (0), color (col)
      {}

      Edge (EdgeType etype, int col, bool alloc_pc_containers)
	: StampableEntity (alloc_pc_containers), e_type (etype), sink_level (0), color (col)
      {}

    public:
      class node_iter
      {
	dbc::PCEntity::Econtainer::iterator it;

      public:
	node_iter (dbc::PCEntity::Econtainer::iterator i)
	  : it (i)
	{}

	node_iter& operator++ ()
	{ ++ it; return *this; }

	node_iter operator++ (int)
	{ node_iter tmp = *this; ++it; return tmp; }

	Node* operator* ()
	{ return reinterpret_cast<Node*> ((*it).get ()); }

	bool operator== (const node_iter& i)
	{ return it == i.it; }

	bool operator!= (const node_iter& i)
	{ return it != i.it; }

	inline dbc::PCEntity::Econtainer::iterator get ()
	{ return it; }
      };

    public:
      Edge ()
      {}

      inline EdgeType get_etype ()
      { return e_type; }

      /// Nodes that produces inputs into edge
      inline void add_in_node (Node* node);

      /// Nodes that consumes edge outputs
      inline void add_out_node (Node* node);

      inline node_iter begin_in_node ();
      inline node_iter end_in_node ();

      inline node_iter begin_out_node ();
      inline node_iter end_out_node ();

      inline void set_sink_level (int l)
      { sink_level = l; }

      inline int get_sink_level ()
      { return sink_level; }

      inline int get_color ()
      { return color; }

      inline void set_color (int c)
      { color = c; }

      /* Transform production form in nodes to consumption to out nodes */
      virtual void transform () = 0;
    };
  };
};

#endif
